package com.yuanjing.xiangqinxiangai.util

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.ImageFormat
import android.graphics.Paint
import android.graphics.YuvImage
import android.view.TextureView
import com.yuanjing.xiangqinxiangai.MyApp
import com.yuanjing.xiangqinxiangai.liveMessagePlugin
import com.yuanjing.xiangqinxiangai.model.AppConfig
import im.zego.zegoexpress.ZegoExpressEngine
import im.zego.zegoexpress.callback.IZegoEventHandler
import im.zego.zegoexpress.constants.ZegoAudioDeviceMode
import im.zego.zegoexpress.constants.ZegoPlayerState
import im.zego.zegoexpress.constants.ZegoPublishChannel
import im.zego.zegoexpress.constants.ZegoPublisherState
import im.zego.zegoexpress.constants.ZegoRemoteDeviceState
import im.zego.zegoexpress.constants.ZegoRoomStateChangedReason
import im.zego.zegoexpress.constants.ZegoScenario
import im.zego.zegoexpress.constants.ZegoStreamEvent
import im.zego.zegoexpress.constants.ZegoStreamResourceMode
import im.zego.zegoexpress.constants.ZegoUpdateType
import im.zego.zegoexpress.constants.ZegoVideoMirrorMode
import im.zego.zegoexpress.constants.ZegoViewMode
import im.zego.zegoexpress.entity.ZegoCanvas
import im.zego.zegoexpress.entity.ZegoCustomVideoCaptureConfig
import im.zego.zegoexpress.entity.ZegoEngineProfile
import im.zego.zegoexpress.entity.ZegoPlayerConfig
import im.zego.zegoexpress.entity.ZegoRoomConfig
import im.zego.zegoexpress.entity.ZegoStream
import im.zego.zegoexpress.entity.ZegoUser
import im.zego.zegoexpress.entity.ZegoVideoConfig
import im.zego.zegoexpress.entity.ZegoVideoFrameParam
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
import org.json.JSONObject
import java.io.ByteArrayOutputStream
import java.nio.ByteBuffer


object LiveEngineUtil {
    private var ownerBitmapListener: OwnerBitmapListener? = null

    lateinit var engine: ZegoExpressEngine

    var isFirstLoad = true


    fun init(appConfig: AppConfig) {
        engine = createEngine(
            appConfig.jgAppId.toLong(),
            appConfig.jgAppSign,
            object : IZegoEventHandler() {
                override fun onRoomStreamUpdate(
                    roomID: String?,
                    updateType: ZegoUpdateType?,
                    streamList: ArrayList<ZegoStream>,
                    extendedData: JSONObject?
                ) {
                    when (updateType) {
                        ZegoUpdateType.DELETE -> {
//                                streamList.forEach {
//                                    engine.stopPlayingStream(it.streamID)
//                                }
                        }

                        ZegoUpdateType.ADD -> {
                        }

                        else -> {}
                    }
                }

                override fun onPublisherStateUpdate(
                    streamID: String,
                    state: ZegoPublisherState,
                    errorCode: Int,
                    extendedData: JSONObject?
                ) {
                    super.onPublisherStateUpdate(streamID, state, errorCode, extendedData)

                    when (errorCode) {
                        0 -> {
                            when (state) {
                                ZegoPublisherState.PUBLISHING -> {
                                }

                                ZegoPublisherState.NO_PUBLISH -> {
                                }

                                ZegoPublisherState.PUBLISH_REQUESTING -> {

                                }
                            }
                        }

                        1002050 -> {
//                                ActivityUtils.getTopActivity()?.let {
//                                    ZZDialogUtil.showMessageDialog(
//                                        it, "退出提示", "您的账号在其他手机登录",
//                                        "确定", {
//                                            ActivityUtils.finishActivity(LiveActivity::class.java)
//                                        }, canCancel = false
//                                    )
//                                }
                        }
                    }
                }

                override fun onPublisherStreamEvent(
                    eventID: ZegoStreamEvent?,
                    streamID: String?,
                    extraInfo: String?
                ) {

                }

                override fun onPlayerStreamEvent(
                    eventID: ZegoStreamEvent,
                    streamID: String,
                    extraInfo: String?
                ) {
                    super.onPlayerStreamEvent(eventID, streamID, extraInfo)
                    when (eventID) {
                        ZegoStreamEvent.PLAY_START, ZegoStreamEvent.PLAY_SUCCESS,
                        ZegoStreamEvent.RETRY_PLAY_START, ZegoStreamEvent.RETRY_PLAY_SUCCESS,
                        ZegoStreamEvent.PUBLISH_START, ZegoStreamEvent.PUBLISH_SUCCESS,
                        ZegoStreamEvent.RETRY_PUBLISH_START, ZegoStreamEvent.RETRY_PUBLISH_SUCCESS -> {
                        }

                        ZegoStreamEvent.PLAY_END, ZegoStreamEvent.PLAY_FAIL,
                        ZegoStreamEvent.RETRY_PLAY_FAIL, ZegoStreamEvent.PUBLISH_FAIL,
                        ZegoStreamEvent.PUBLISH_END, ZegoStreamEvent.RETRY_PUBLISH_FAIL -> {
                        }

                        else -> {}
                    }
                }

                override fun onRoomUserUpdate(
                    roomID: String,
                    updateType: ZegoUpdateType,
                    userList: ArrayList<ZegoUser>
                ) {
                    when (updateType) {
                        ZegoUpdateType.ADD -> {
                            if (isFirstLoad) {
                                isFirstLoad = false
                                return
                            }
                        }

                        ZegoUpdateType.DELETE -> {

                        }
                    }
                }

                override fun onRoomOnlineUserCountUpdate(roomID: String, count: Int) {
                }

                override fun onRoomStateChanged(
                    roomID: String?,
                    reason: ZegoRoomStateChangedReason?,
                    errorCode: Int,
                    extendedData: JSONObject?
                ) {


                    when (reason) {
//                            ZegoRoomStateChangedReason.KICK_OUT, ZegoRoomStateChangedReason.LOGOUT -> {
//                                RoomCloseEvent(
//                                    reason,
//                                    extendedData?.optString(CUSTOM_KICK_OUT_MESSAGE)
//                                ).postEvent()
//                            }

                        else -> {

                        }
                    }
                }

                override fun onRemoteMicStateUpdate(
                    streamID: String?,
                    state: ZegoRemoteDeviceState?
                ) {
                    if (state == ZegoRemoteDeviceState.OPEN || state == ZegoRemoteDeviceState.MUTE) {
                    }
                }

                override fun onPlayerStateUpdate(
                    streamID: String,
                    state: ZegoPlayerState,
                    errorCode: Int,
                    extendedData: JSONObject?
                ) {

                    if (errorCode != 0) {
                        return
                    }
                    when (state) {
                        ZegoPlayerState.PLAYING -> {
                        }

                        ZegoPlayerState.NO_PLAY -> {
                        }

                        ZegoPlayerState.PLAY_REQUESTING -> {
                        }
                    }
                }

                override fun onRemoteCameraStateUpdate(
                    streamID: String,
                    state: ZegoRemoteDeviceState
                ) {
                    when (state) {
                        ZegoRemoteDeviceState.MUTE -> {
                        }

                        ZegoRemoteDeviceState.OPEN -> {
                        }

                        else -> {}
                    }
                }

            })
//                _engine?.enableHardwareEncoder(SettingUtil.enableHardPrase())
        // H265 need hardware encode(publishing) and hardware decoder(playing)
//                engine.enableHardwareEncoder(SettingUtil.enableHardPrase())
//                engine.enableHardwareDecoder(SettingUtil.enableHardPrase())
        engine.setAudioDeviceMode(ZegoAudioDeviceMode.GENERAL)

    }

    fun getVideoStreamState() {

    }

    fun enableCustomVideoCapture(videoCaptureConfig: ZegoCustomVideoCaptureConfig) {
        engine.enableCustomVideoCapture(true, videoCaptureConfig, ZegoPublishChannel.MAIN)
    }

    fun sendCustomVideoCaptureRawData(
        byteBuffer: ByteBuffer,
        param: ZegoVideoFrameParam,
        now: Long
    ) {
        ownerBitmapListener?.let { it1 ->
            ownerBitmapListener = null
            val bitmap = nv21ToBitmap(byteBuffer, param.width, param.height)
            it1.call(bitmap!!)
        }
        engine.sendCustomVideoCaptureRawData(byteBuffer, byteBuffer.limit(), param, now)
    }

    fun nv21ToBitmap(byteBuffer: ByteBuffer, width: Int, height: Int): Bitmap? {
        // NV21 数据的总长度
        val size = byteBuffer.remaining()

        // 创建 YUVImage 对象，用于处理 NV21 数据
        val yuvImage = YuvImage(byteBuffer.array(), ImageFormat.NV21, width, height, null)

        // 将 YUVImage 转换为 JPEG，以便进一步处理
        val outStream = ByteArrayOutputStream()
        if (!yuvImage.compressToJpeg(android.graphics.Rect(0, 0, width, height), 100, outStream)) {
            return null
        }

        // 将 JPEG 数据解码为 Bitmap
        val jpegData = outStream.toByteArray()
        return BitmapFactory.decodeByteArray(jpegData, 0, jpegData.size)
    }

    private fun createEngine(
        ZEGO_APP_ID: Long,
        ZEGO_SIGN: String,
        eventHandler: IZegoEventHandler
    ): ZegoExpressEngine {
        val profile = ZegoEngineProfile()
        profile.appID = ZEGO_APP_ID
        profile.appSign = ZEGO_SIGN
        profile.scenario = ZegoScenario.DEFAULT
        profile.application = MyApp.instance

        return ZegoExpressEngine.createEngine(profile, eventHandler)
    }


    fun startPreview(texture: TextureView?) {
        var zegoCanvas: ZegoCanvas? = null
        texture?.let {
            zegoCanvas = ZegoCanvas(texture)
            zegoCanvas?.viewMode = ZegoViewMode.ASPECT_FILL
        }
        engine.startPreview(zegoCanvas)
    }

    fun isPublishing(streamId: String?): Boolean {
        return currentStreamId == streamId && isPublish
    }

    fun isPublishing(): Boolean {
        return isPublish
    }

    private var currentStreamId: String? = null
    private var isPublish: Boolean = false

    fun startPublish(
        streamId: String?,
        zegoConfig: ZegoVideoConfig? = null,
        isCamera: Boolean = true,
    ) {
        if (streamId.isNullOrEmpty()) {
            return
        }
        isPublish = true
        currentStreamId = streamId
        val videoConfig = zegoConfig ?: ZegoVideoConfig()
//        if (width != 0 && height != 0) {
//            videoConfig.captureWidth = width
//            videoConfig.captureHeight = height
//            videoConfig.encodeWidth = width
//            videoConfig.encodeHeight = height
//        }
//        videoConfig.fps = 12
//        videoConfig.bitrate = 1200
//        engine.videoConfig = videoConfig
        engine.setVideoMirrorMode(ZegoVideoMirrorMode.BOTH_MIRROR)
        engine.startPublishingStream(streamId)
        engine.enableCamera(isCamera)
        engine.setCaptureVolume(180)
        engine.mutePublishStreamVideo(false)
        engine.muteMicrophone(false)

    }


    fun pausePublish() {
        engine.mutePublishStreamVideo(true)
    }

    fun resumePublish() {
        engine.mutePublishStreamVideo(false)
    }

    //设置静音
    fun mute(isMute: Boolean) {
        engine.muteMicrophone(isMute)
    }

    //设置所有音效的本地播放音量
    fun setPlayVolumeAll(int: Int = 100) {
        engine.setAllPlayStreamVolume(int)
    }

    fun stopPublish() {
        isPublish = false
        engine.stopPreview()
        engine.stopPublishingStream()

    }


    fun outRoom() {
        engine.stopPreview()
        engine.stopPublishingStream()
        engine.logoutRoom()
    }


    suspend fun screenCapture(): Bitmap? {
//        return null
        return withContext(Dispatchers.IO) {
            val scaledBitmaps = mutableListOf<Bitmap>()
            suspendTakePublishStreamSnapshot()?.let {
                scaledBitmaps.add(scaledBitmap(it))
            }
            liveMessagePlugin?.livePreviewMap?.forEach { it ->
                it.value?.let { item ->
                    var mai = item.roomMais
                    if (mai.outputStreamId != null && !mai.isAnchor()) { //有流id，并且 不是自己的麦
                        val bitmap = withContext(Dispatchers.Main) {
                            suspendTakeSnapshot(mai.outputStreamId!!)
                        }
                        bitmap?.let {
                            scaledBitmaps.add(scaledBitmap(bitmap))
                        }
                    }
                }

            }
            if (scaledBitmaps.isEmpty()) return@withContext null
            val totalHeight = scaledBitmaps.sumBy { it.height }
            val combinedBitmap = Bitmap.createBitmap(360, totalHeight, Bitmap.Config.RGB_565)
            val canvas = Canvas(combinedBitmap)
            val paint = Paint()
            var currentHeight = 0
            scaledBitmaps.forEach { bitmap ->
                canvas.drawBitmap(bitmap, 0f, currentHeight.toFloat(), paint)
                currentHeight += bitmap.height
            }

            combinedBitmap
        }
    }

    fun scaledBitmap(bitmap: Bitmap): Bitmap {
        val originalWidth = bitmap.width
        val originalHeight = bitmap.height
        val targetWidth = 360
        // 计算等比缩放后的高度
        val scaleFactor = targetWidth.toFloat() / originalWidth.toFloat()
        val targetHeight = (originalHeight * scaleFactor).toInt()
        return Bitmap.createScaledBitmap(
            bitmap,
            targetWidth,
            targetHeight,
            true
        )
    }

    private suspend fun suspendTakeSnapshot(stream: String): Bitmap? {
        return withContext(Dispatchers.Main) {
            suspendCancellableCoroutine { continuation ->

                engine.takePlayStreamSnapshot(stream) { errorCode: Int, image: Bitmap? ->
                    if (errorCode == 0 && image != null) {
                        continuation.resume(image) {}
                    } else {
                        continuation.resume(null) {}
                    }
                }
            }
        }
    }

    private suspend fun suspendTakePublishStreamSnapshot(): Bitmap? {
        return withContext(Dispatchers.Main) {
            suspendCancellableCoroutine { continuation ->

//                ownerBitmapListener = object : OwnerBitmapListener {
//                    override fun call(bitmap: Bitmap) {
//                        continuation.resume(bitmap) {}
//                    }
//                }
                engine.takePublishStreamSnapshot() { errorCode: Int, image: Bitmap? ->
                    if (errorCode == 0 && image != null) {
                        continuation.resume(image) {}
                    } else {
                        continuation.resume(null) {}
                    }
                }
            }
        }
    }
}

interface OwnerBitmapListener {
    fun call(bitmap: Bitmap)
}
